﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using EzyThirdLogic.ExtensionMethods;

namespace EzyThirdLogic
{
    public class Merger
    {
        List<FunctionalDependencySet> J = new List<FunctionalDependencySet>();

        public FunctionalDependencySetCollection Merge(FunctionalDependencySetCollection fdSetCollection, FunctionalDependencySet fdSet)
        {
            FunctionalDependencySetCollection newB = new FunctionalDependencySetCollection();

            List<FunctionalDependencySet> fds = new List<FunctionalDependencySet>();
            List<FunctionalDependency> closure = new List<FunctionalDependency>();

            foreach (FunctionalDependencySet fds1 in fdSetCollection.FDSetCollection)
            {
                fds.Add(fds1);
                FunctionalDependency fd1 = fds1.FDSet.First<FunctionalDependency>();
                BitArray fd1LeftBitArray = fd1.BitDeterminant;
                BitArray temp = SynthesizingAlgorithm.AttributeClosure(fdSet, fd1LeftBitArray);
                closure.Add(new FunctionalDependency(FunctionalDependency.ToStringWithDelimiter(temp), fd1.LeftToStringWithDelimiter()));
            }

            closure.Sort();
            fds.Sort();

            int a = closure.Count;
            string[] s = new string[a];
            for (int i = 0; i < closure.Count; i++)
            {
                var fd = closure[i];
                s[i] = fd.LeftToString();
            }

            List<string> store = new List<string>();
            var tmp = s[0];
            store.Add(closure[0].RightToString());
            if (a > 1)
            {
                for (int i = 1; i < closure.Count; i++)
                {
                    if (s[i].Equals(tmp))
                    {
                        store.Add(closure[i].RightToString());
                    }

                    if (!s[i].Equals(tmp) || i == closure.Count - 1)
                    {
                        tmp = s[i];
                        if (store.Count > 1)
                        {
                            var newfds = new FunctionalDependencySet();
                            for (int m = 0; m < store.Count; m++)
                            {
                                for (int n = 0; n < store.Count; n++)
                                {
                                    if (m < n)
                                    {
                                        newfds = BuildJ(newfds, store[m], store[n]);
                                    }
                                }
                            }

                            var newUnionH = new FunctionalDependencySet();
                            for (int n = 0; n < store.Count; n++)
                            {
                                for (int m = 0; m < fds.Count; m++)
                                {
                                    var fd = fds[m].FDSet.ElementAt<FunctionalDependency>(0);
                                    if (fd.LeftToString() == store[n])
                                    {
                                        newUnionH = BuildH(newUnionH, newfds, fds[m]);
                                    }
                                }
                            }

                            for (int m = store.Count - 1; m >= 0; m--)
                            {
                                //store.Remove(m.ToString());
                                store.RemoveAt(m);
                            }

                            J.Add(newfds);
                            newB.FDSetCollection.Add(newfds);
                            newB.FDSetCollection.Add(newUnionH);

                            if (i != closure.Count - 1)
                            {
                                store.Add(closure[i].RightToString());
                            }
                        }
                        else
                        {
                            for (int m = 0; m < fds.Count; m++)
                            {
                                var fd = fds[m].FDSet.ElementAt<FunctionalDependency>(0);
                                if (fd.LeftToString() == store[0])
                                {
                                    newB.FDSetCollection.Add(fds[m]);
                                    break;
                                }
                            }

                            store.RemoveAt(0);
                            store.Add(closure[i].RightToString());

                            if (i == closure.Count - 1)
                            {
                                for (int m = 0; m < fds.Count; m++)
                                {
                                    var fd = fds[m].FDSet.ElementAt<FunctionalDependency>(0);
                                    if (fd.LeftToString() == store[0])
                                    {
                                        newB.FDSetCollection.Add(fds[m]);
                                        break;
                                    }
                                }
                                store.RemoveAt(0);
                            }
                        }
                    }
                }
            }
            else
            {
                newB.FDSetCollection.Add(fds[0]);
            }

            return newB;
        }

        public FunctionalDependencySet BuildJ(FunctionalDependencySet newFDSet, string x, string y)
        {
            FunctionalDependency addition1 = new FunctionalDependency(AddDelimiter(x), AddDelimiter(y));
            FunctionalDependency addition2 = new FunctionalDependency(AddDelimiter(y), AddDelimiter(x));

            newFDSet.AddFunctionalDependency(addition1);
            newFDSet.AddFunctionalDependency(addition2);

            return newFDSet;
        }

        //Build Union H = Hi - J
        public FunctionalDependencySet BuildH(FunctionalDependencySet newUnionH, FunctionalDependencySet newFDSet, FunctionalDependencySet fds1)
        {
            newFDSet = SynthesizingAlgorithm.AllSingleRHSAttr(newFDSet); //J
            fds1 = SynthesizingAlgorithm.AllSingleRHSAttr(fds1); //H1

            foreach (FunctionalDependency fd in fds1.FDSet)
            {
                newUnionH.AddFunctionalDependency(fd);
            }
            var tempSet = newUnionH.Clone();

            bool removed = false;
            foreach (FunctionalDependency fd in newFDSet.FDSet)
            {
                removed = false;
                foreach (FunctionalDependency fd1 in tempSet.FDSet)
                {
                    if (removed == true) break;
                    if (fd.CompareTo(fd1) == 0)
                    {
                        newUnionH.RemoveFunctionalDependency(fd1);
                        removed = true;
                    }
                }
            }
            return newUnionH;
        }

        public string[][] GetArrayJ()
        {
            String[][] fds = new String[10][];
            for (int i = 0; i < fds.Length; i++)
            {
                fds[i] = new String[2];
            }

            int index = 0;

            if (J.Count > 0)
            {
                for (int i = 0; i < J.Count; i++)
                {
                    var fdSet = J.ElementAt<FunctionalDependencySet>(i).FDSet;
                    foreach (FunctionalDependency fd in fdSet)
                    {
                        fds[index][0] = AddDelimiter2(fd.LeftToString());
                        fds[index][1] = AddDelimiter2(fd.RightToString());
                        index++;
                    }
                }
            }

            return fds;
        }

        public List<FunctionalDependencySet> GetJ()
        {
            return J;
        }

        //Add delimiter "," to a string
        public String AddDelimiter(String str)
        {
            String left = "";
            for (int i = 0; i < str.Length; i++)
            {
                if (i != 0)
                    left += "";
                left += str.Substring(i, 1);
                left += ",";
            }
            return left;
        }

        public String AddDelimiter2(String s)
        {
            String newString = "";
            for (int i = 0; i < s.Length; i++)
            {
                newString += s.Substring(i, 1);
                if (i + 1 != s.Length)
                    newString += ",";
            }
            return newString;
        }
    }
}
